﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using PowersourceUIToolkit;
using UCL.Powersource.TFS;
using System.ComponentModel.Composition.Primitives;
using System.Windows;
using System.Windows.Markup;
using System.IO;

namespace UCL.Powersource
{
    public abstract class PowersourceBootstrapperBase : Bootstrapper
    {
        public const string KEY_Bootstrapper = "bootstrapper";

        protected IUIManager UIManager { get; set; }
        protected IStatisticManager StatisticManager { get; set; }
        protected IReportingManager ReportingManager { get; set; }
        protected IPowersourceExt IPowersourceExt { get; set; }
        protected IVSEnv IVsEnv { get; set; }
        protected ITfsTeamProjectCollectionFactory TfsTeamProjectCollectionFactory { get; set; }
        protected IPackageConfigurationFactory PackageConfigurationFactory { get; set; }
        protected Type[] TypesToLoad { get; set; }
        protected Dictionary<Type, Type> DefaultInterfaceImplementationTypes { get; set; }
        protected IStatisticManagerQueue StatisticManagerQueue { get; set; }
        protected IRemoteBuilderQueue RemoteBuilderQueue { get; set; }

        private CompositionContainer container;

        public PowersourceBootstrapperBase()
        {
            Debug.WriteLine("In PowersourceBootstrapperBase constructor");
            DefaultInterfaceImplementationTypes = new Dictionary<Type, Type>();

        }

        protected override object GetInstance(Type serviceType, string key)
        {
            Debug.WriteLine("[{0}] : GetInstance {1} key {2} ", this, serviceType.Name, key);
            string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
            var exports = container.GetExportedValues<object>(contract);

            if (exports.Count() > 0)
                return exports.First();

            throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
        }

        protected override IEnumerable<object> GetAllInstances(Type serviceType)
        {
            return container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
        }

        protected override void BuildUp(object instance)
        {
            container.SatisfyImportsOnce(instance);
        }

        protected override Type GetDefaultInterfaceImplementationType(Type interfaceType)
        {
            Type retVal = null;
            if (DefaultInterfaceImplementationTypes != null && DefaultInterfaceImplementationTypes.ContainsKey(interfaceType))
            {
                retVal = DefaultInterfaceImplementationTypes[interfaceType];
            }
            return retVal;
        }

        protected override IEnumerable<Type> GetDefaultInterfaceImplementationTypes()
        {
            if (DefaultInterfaceImplementationTypes == null) return new Type[0];
            return DefaultInterfaceImplementationTypes.Values;
        }

        protected override void OnDisposing()
        {
            ViewModelLocator.DisposeViewModels(true);
            ViewLocator.DisposeViews(true);
            if (IPowersourceExt != null)
            {
                if (IPowersourceExt.ReportingManager != null) IPowersourceExt.ReportingManager.Dispose();
                if (IPowersourceExt.StatisticManager != null) IPowersourceExt.StatisticManager.Dispose();
                if (IPowersourceExt.UIManager != null) IPowersourceExt.UIManager.Dispose();
                if (RemoteBuilderQueue != null) RemoteBuilderQueue.Dispose();
                if (StatisticManagerQueue != null) StatisticManagerQueue.Dispose();
            }
            PowersourceConnector.CleanUp();
            container.Dispose();
            base.OnDisposing();
        }


        /// <summary>
        /// Current only load Powersource assemblyFile 
        /// </summary>
        /// <returns>A list of assemblies to inspect.</returns>
        protected internal override IEnumerable<Assembly> SelectAssemblies()
        {
            var list = new List<Assembly>();
            var gea = Assembly.GetExecutingAssembly();
            list.Add(gea);
            var sharedEA = typeof(Bootstrapper).Assembly;
            list.Add(sharedEA);

            //try
            //{
            //    using (StreamReader fs = new StreamReader("extensibility.config"))
            //    {
            //        while (!fs.EndOfStream)
            //        {
            //            var r=fs.ReadLine();
            //        }
            //    }
            //}
            //catch (Exception exc)
            //{
            //    Log.Error(exc, "Error while loading extension files!");
            //    throw;
            //}
            if (TypesToLoad != null)
            {
                foreach (var item in TypesToLoad)
                {
                    list.Add(item.Assembly);
                }
            }



            return list.Distinct();
        }


        protected override void InitializeIoCDependants()
        {
            Debug.WriteLine("[{0}] : Initializing Connector and IoC dependants", this);
            PowersourceConnector.Configure(IPowersourceExt);
            IPowersourceExt.ReportingManager.Initialize();
            IPowersourceExt.StatisticManager.Initialize();
            foreach (var stat in IPowersourceExt.StatisticManager.AvailableStatistics.Values)
            {
                Log.Trace("{0} available in Statistic Manager", stat.Name);
            }
            foreach (var rep in IPowersourceExt.ReportingManager.StatisticViewModels)
            {
                Log.Trace("{0} available in Reporting Manager", rep.Label);
            }

        }

        public const string DefaultResourceFilename = "DefaultResourceDictionary.xaml";

        protected override void Configure()
        {
            Debug.WriteLine("[{0}] : Load Resources", this);

            //DefaultResourceDictionary = new ResourceDictionary();

            //if (File.Exists(DefaultResourceFilename))
            //{
            //    using (var f = File.Open(DefaultResourceFilename, FileMode.Open, FileAccess.Read))
            //    {
            //        DefaultResourceDictionary = (ResourceDictionary)(XamlReader.Load(f));
            //    }

            //}



            Debug.WriteLine("[{0}] : Configure", this);

            var catalog = new AggregateCatalog(
                    AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
                    );

            container = new CompositionContainer(catalog);
            var batch = new CompositionBatch();

            batch.AddExportedValue<IUIManager>(UIManager);
            //batch.AddExportedValue<IEventAggregator>(new EventAggregator());
            batch.AddExportedValue<ILog>(LogManager.GetLog(null));

            batch.AddExportedValue<IStatisticManager>(StatisticManager);
            batch.AddExportedValue<IReportingManager>(ReportingManager);
            batch.AddExportedValue<IPowersourceExt>(IPowersourceExt);
            batch.AddExportedValue<IVSEnv>(IVsEnv);
            batch.AddExportedValue<ITfsTeamProjectCollectionFactory>(TfsTeamProjectCollectionFactory);
            batch.AddExportedValue<IPackageConfigurationFactory>(PackageConfigurationFactory);
            batch.AddExportedValue<IStatisticManagerQueue>(StatisticManagerQueue);
            batch.AddExportedValue<IRemoteBuilderQueue>(RemoteBuilderQueue);


            batch.AddExportedValue(container);
            batch.AddExportedValue(catalog);
            Debug.WriteLine("[{0}] : Composing container", this);
            container.Compose(batch);
            Debug.WriteLine("[{0}] : Configure done", this);

        }
    }
}
